// 工具注册与管理
// 作用：统一管理所有工具，帮 Agent 解决 “怎么找工具、怎么用工具” 的问题。
// 关键设计：
// 用 Map 存储工具（按工具名索引），方便快速查找。
// 提供 register（注册工具）、getTool（获取工具）、execute（执行工具）方法，封装工具调用逻辑。
import { SearchTool, CalculatorTool, TimeTool, GeocodingTool, WeatherTool } from "./tools";
import { CodeExecutionTool, DataAnalysisTool } from "./code.tools";

// 统一管理所有工具
const DEFAULT_TOOLS = [
  new SearchTool(),
  new CalculatorTool(),
  new TimeTool(),
  new GeocodingTool(),
  new WeatherTool(),
  new CodeExecutionTool(),
  new DataAnalysisTool()
];


export class ToolManager {
  private tools = new Map<string, any>();

  constructor(tools: any[] = DEFAULT_TOOLS) {
    // 批量注册工具
    tools.forEach(tool => this.register(tool));
    console.log("已注册工具：", Array.from(this.tools.keys()));
  }

  register(tool: any) {
    this.tools.set(tool.name, tool);
  }

  getTool(name: string) {
    return this.tools.get(name);
  }

  /**
   * 验证并预处理输入参数
   * 1. 处理参数别名（如 equation -> expression）
   * 2. 使用 Zod schema 进行校验和类型转换
   */
  validateAndPreprocess(name: string, input: any): any {
    const tool = this.getTool(name);
    if (!tool) return input;

    const mappedInput = { ...input };

    // 1. 处理参数别名
    if (tool.parameterAliases) {
      const aliases = tool.parameterAliases as Record<string, string>;
      for (const [alias, target] of Object.entries(aliases)) {
        // 如果输入中包含别名，且不包含目标名，则进行映射
        if (alias in mappedInput && !(target in mappedInput)) {
          mappedInput[target] = mappedInput[alias];
          delete mappedInput[alias];
        }
      }
    }

    // 2. 使用 Zod schema 进行校验
    // safeParse 不会抛出异常，而是返回 result 对象
    // 我们优先使用解析后的数据（可能包含 default 值或类型转换）
    if (tool.schema) {
       const result = tool.schema.safeParse(mappedInput);
       if (result.success) {
         return result.data;
       } else {
         // 如果校验失败，为了兼容性，暂时返回映射后的原始数据
         // 或者在这里抛出异常，让 Agent 捕获并反馈给 LLM
         console.warn(`工具 ${name} 参数校验失败:`, result.error);
         return mappedInput;
       }
    }

    return mappedInput;
  }

  getAllTools() {
    return Array.from(this.tools.values());
  }

  async execute(name: string, args: any) {
    const tool = this.getTool(name);
    if (!tool) throw new Error(`工具 ${name} 不存在`);
    return await tool._call(args);
  }
}
